package com.je.gateway.router.dispatcher;

import com.google.common.base.Strings;
import com.je.gateway.router.GlobalRouterParams;
import com.netflix.config.DynamicPropertyFactory;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import org.apache.servicecomb.edge.core.EdgeInvocation;
import org.apache.servicecomb.transport.rest.vertx.RestBodyHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UrlFirstCharacterEdgeDispatcher extends GatewayAbstractRestDispatcher {

    private static final Logger logger = LoggerFactory.getLogger(UrlFirstCharacterEdgeDispatcher.class);

    private static final String KEY_ENABLED = "servicecomb.http.dispatcher.edge.headerRouter.product.enabled";

    public UrlFirstCharacterEdgeDispatcher() {
    }

    @Override
    public int getOrder() {
        return 10;
    }

    protected void preCheck(RoutingContext context) {
        String url = context.request().path();
        if (Strings.isNullOrEmpty(url) || !url.contains("/") || "/health".equals(url)) {
            context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.TRUE);
            context.next();
            return;
        }
        context.next();
    }

    @Override
    public void init(Router router) {
        String pattern = GlobalRouterParams.GLOBAL_HEADER_ROUTER.getPath();
        router.routeWithRegex(pattern).failureHandler(this::onFailure)
                .handler(this::preCheck)
                .handler(createBodyHandler())
                .handler(this::onRequest);
    }

    public static String getPdParameterValue(String url) {
        String pdValue = null;

        if (url != null) {
            String[] queryParams = url.split("\\?");
            if (queryParams.length > 1) {
                String[] params = queryParams[1].split("&");
                for (String param : params) {
                    String[] keyValue = param.split("=");
                    if (keyValue.length == 2 && "pd".equals(keyValue[0])) {
                        pdValue = keyValue[1];
                        break;
                    }
                }
            }
        }
        return pdValue;
    }

    protected void onRequest(RoutingContext context) {
        String url = context.request().path();
        if (isGateWayPath(context, context.request().path())) {
            context.next();
            return;
        }
        String microServiceName = url.split("/")[1];
        if (!Strings.isNullOrEmpty(getPdParameterValue(context.request().uri()))) {
            microServiceName = getPdParameterValue(context.request().uri());
        } else if (!Strings.isNullOrEmpty(context.request().getParam("pd"))) {
            microServiceName = context.request().getParam("pd");
        }

        Boolean bypass = context.get(RestBodyHandler.BYPASS_BODY_HANDLER);
        if (Boolean.TRUE.equals(bypass)) {
            // clear flag
            context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.FALSE);
            context.next();
            return;
        }

        EdgeInvocation edgeInvocation = createEdgeInvocation(context);
        edgeInvocation.init(microServiceName, context, url, httpServerFilters);
        logger.info("Matching with UrlFirstCharacter Dispatcher,the path {} pattern with {} is router to {} begin,the real path is {}! headeKey is {} headeValue is {}", context.request().path(), url, microServiceName);
        edgeInvocation.edgeInvoke();
        logger.info("Router url {} to {} complete", context.request().path(), microServiceName);
    }

    @Override
    public boolean enabled() {
        return DynamicPropertyFactory.getInstance().getBooleanProperty(KEY_ENABLED, true).get();
    }
}
